#pragma once
#include <iostream>
#include <string>
#include <memory>
#include <jsoncpp/json/json.h>

const char spaces_sep = ' ';
const char newline_sep = '\n';

std::string Package(const std::string &str)
{
    std::string pstr;
    size_t len = str.size();
    pstr += std::to_string(len);
    pstr += newline_sep;
    pstr += str;
    pstr += newline_sep;
    return pstr;
}

std::string Unpack(const std::string &package)
{
    //"len""\n""正文""\n"
    std::string s;
    size_t left_pos = package.find(newline_sep);
    if (left_pos == std::string::npos)
        return "";

    size_t right_pos = package.rfind(newline_sep);
    if (right_pos == std::string::npos)
        return "";
    size_t len = std::stoi(package.substr(0, left_pos));
    s = package.substr(left_pos + 1, right_pos - left_pos - 1); // right_pos - left_pos - 1['\n']，截取长度
    // std::cout << "s :[" << s << "size:" << s.size() << " len:" << len << "]"  << std::endl;
    if (len != s.size())
        return "";
    return s;
}

class ContentPackage
{
    ContentPackage(int x = 0, int y = 0, char op = spaces_sep)
        : _x(x), _y(y), _op(op)
    {
    }
    ContentPackage(const ContentPackage &) = delete;
    ContentPackage &operator=(const ContentPackage &) = delete;

public:
    void Serialization(std::string &package)
    {
#ifdef USE_JSON
        //"x op y"
        package += std::to_string(_x);
        package += spaces_sep;
        package += _op;
        package += spaces_sep;
        package += std::to_string(_y);
#else
        Json::Value pck;
        pck["x"] = std::to_string(_x);
        pck["op"] = _op;
        pck["y"] = std::to_string(_y);
        
        Json::StyledWriter w;
        package = w.write(pck);
#endif

    }
    bool Deserialization(const std::string &package)
    {
#ifdef USE_JSON
        //"x op y"
        size_t left_pos = package.find(spaces_sep);
        if (left_pos == std::string::npos)
            return false;
        size_t right_pos = package.rfind(spaces_sep);
        if (right_pos == std::string::npos)
            return false;

        if (left_pos + 2 != right_pos)
            return false;

        _x = std::stoi(package.substr(0, left_pos));
        _y = std::stoi(package.substr(right_pos + 1));
        _op = package[left_pos + 1];
        return true;
#else
        Json::Value pck;
        Json::Reader r;
        r.parse(package,pck);

        if(!pck.isMember("x") || !pck["x"].isInt())
        {
            return false;
        }
        if(!pck.isMember("y") || !pck["y"].isInt())
        {
            return false;
        }
        //op存在且为字符
        if(!pck.isMember("op") || !pck["op"].isString() 
            || pck["op"].asString().size() != 1)
        {
            return false;
        }
        _x = pck["x"].asInt();
        _op = pck["op"].asCString()[0];
        _y = pck["y"].asInt();
        return true;
#endif
    };

    static ContentPackage &Getinitance(int x = 0, int y = 0, char op = spaces_sep)
    {
        static ContentPackage _this(x, y, op);
        return _this;
    }

    void AddDate(int x,int y,char op)
    {
        _x = x;
        _y = y;
        _op = op;
    }

    int Getx() const { return _x; };
    int Gety() const { return _y; };
    char Getop() const { return _op; };

private:
    int _x;
    int _y;
    char _op;
};

enum Code
{
    Correct,
    DivisionError,
    FormatError,
    LabelError
};
class ResultPackage
{
    ResultPackage(int result = 0, int code = 0)
        : _result(result), _code(code)
    {
    }
    ResultPackage(const ResultPackage &) = delete;
    ResultPackage &operator=(const ResultPackage &) = delete;

public:
    void Serialization(std::string &package)
    {
#ifdef USE_JSON
        //"_result _code"
        package += std::to_string(_result);
        package += spaces_sep;
        package += std::to_string(_code);
#else
        Json::Value pck;
        pck["result"] = std::to_string(_result);
        pck["code"] = std::to_string(_code);

        Json::StyledWriter w;
        package = w.write(pck);
#endif    
    }
    bool Deserialization(const std::string &package)
    {
#ifdef USE_JSON 
        //"_result _code"
        size_t pos = package.find(spaces_sep);
        if (pos == std::string::npos)
            return false;
        _result = std::stoi(package.substr(0, pos));
        _code = std::stoi(package.substr(pos + 1));
        return true;
#else
        Json::Value pck;
        Json::Reader r;
        r.parse(package,pck);

        if(!pck.isMember("result") || !pck["result"].isInt())
        {
            return false;
        }
        if(!pck.isMember("code") || !pck["code"].isInt())
        {
            return false;
        }
        
        _result = pck["result"].asInt();
        _code = pck["code"].asInt();
        return true;
#endif
    };
    void AddDate(int result,int code)
    {
        _result = result;
        _code = code;
    }

    static ResultPackage &Getinitance(int result = 0, int code = 0)
    {
        static ResultPackage _this(result, code);
        return _this;
    }

    int GetResult() const { return _result; }
    int GetCode() const { return _code; }

private:
    int _result;
    int _code;
};